package com.starhub.api.document.service;

import cn.hutool.core.util.StrUtil;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import javax.imageio.ImageIO;

import com.alibaba.fastjson.JSONObject;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFTableCell.XWPFVertAlign;
import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STNumberFormat;
//import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 基于POI将HTML或富文本内容转换为docx文档
 */
public class HtmlToWordService {

    private static final Logger log = LoggerFactory.getLogger(HtmlToWordService.class);

    /**
     * 将HTML内容转换为Word文档内容
     *
     * //@param document Word文档对象
     * @param html     HTML内容
     */
    public static XWPFDocument htmlConvertWord(String html) {
        if (StrUtil.isEmpty(html)) {
            return new XWPFDocument();
        }
        try {
            Document parsedHtml = Jsoup.parse(html);

            // 初始化html数据
            initHtmlData(parsedHtml);

            Elements bodyChildren = parsedHtml.body().children();
            Map<String, Object> initStyle = new HashMap<>();

            XWPFDocument document = new XWPFDocument();
            // 创建初始段落（防止空指针）
            XWPFParagraph initPara = document.createParagraph();

            if (!bodyChildren.isEmpty()) {
                for (Node node : bodyChildren) {
                    for(Attribute attribute :node.attributes()){
                        initStyle.put(attribute.getKey(),attribute.getValue());
                    }
                    System.out.println(JSONObject.toJSONString(initStyle));
                    processElement(node, initPara, initStyle, null, null);
                }
            }
            return document;
        } catch (Exception e) {
            log.error("HTML转换Word失败", e);
        }
        return new XWPFDocument();
    }

    /**
     * 处理html数据。li标签内统一加上p标签（jsoup生成li，如果ul只有一个li没有p标签）
     */
    private static void initHtmlData(Document parsedHtml) {
        for (Element li : parsedHtml.select("li")) {
            // 跳过已有<p>的列表项
            if (!li.select("p").isEmpty()) {
                continue;
            }

            // 获取所有子节点（包括文本和元素）
            List<Node> originalNodes = new ArrayList<>();
            for (Node node : li.childNodes()) {
                // 必须克隆节点！
                originalNodes.add(node.clone());
            }

            // 清空原内容
            li.empty();

            // 创建包裹的<p>标签
            Element p = li.appendElement("p");

            // 重新添加原有内容
            for (Node node : originalNodes) {
                p.appendChild(node);
            }
        }
    }

    /**
     * 递归解析html的结构
     *
     * @param node     节点
     * @param para     段落
     * @param styleMap 样式集合
     * @param cell     table的单元格
     * @param numId    列表的序号
     */
    public static void processElement(Node node, XWPFParagraph para, Map<String, Object> styleMap,
                                      XWPFTableCell cell, BigInteger numId) {
        if (node instanceof TextNode) {
            String text = ((TextNode) node).text().trim();
            if (!text.isEmpty()) {
                XWPFRun run = para.createRun();
                run.setText(text);
                applyStyle(run, para, styleMap);
            }
        } else if (node instanceof Element) {
            Element el = (Element) node;
            String tag = el.tagName().toLowerCase();

            switch (tag) {
                case "h1":
                case "h2":
                case "h3":
                case "h4":
                case "h5":
                case "h6":
                    processHeading(para.getDocument(), el, styleMap);
                    break;
                case "p":
                    processParagraph(para.getDocument(), el, styleMap, cell, numId);
                    break;
                case "span":
                case "strong":
                case "i":
                case "b":
                case "u":
                case "s":
                case "em":
                    processLabStyle(para, styleMap, el);
                    break;
                case "ul":
                case "ol":
                    processList(para.getDocument(), el, styleMap);
                    break;
                case "li":
                    processLi(para, styleMap, numId, el);
                    break;
                case "table":
                    processTable(para.getDocument(), el, styleMap);
                    break;
                case "img":
                    processImage(para.getDocument(), el);
                    break;
                case "hr":
                    createHorizontalRule(para.getDocument());
                    break;
                case "br":
                    createLineBreak(para.getDocument(), cell);
                    break;
                // 其他标签可扩展
                default:
                    for (Node child : el.childNodes()) {
                        processElement(child, para, styleMap, null, numId);
                    }
                    break;
            }
        }
    }

    /**
     * 解析li标签
     */
    private static void processLi(XWPFParagraph para, Map<String, Object> styleMap,
                                  BigInteger numId, Element el) {
        List<Element> children = el.children();
        // li 下面只有p标签，可能会多个p
        for (int i = 0; i < children.size(); i++) {
            if (i != 0) {
                // 第一个li下面的p对应到word的li，递归到p标签处理
                // 标记值 -1
                numId = BigInteger.valueOf(-1);
            }
            processElement(children.get(i), para, styleMap, null, numId);
        }
    }

    /**
     * 样式标签
     */
    private static void processLabStyle(XWPFParagraph para, Map<String, Object> styleMap, Element el) {
        roundProcessElement(el, styleMap, para);
    }

    public static void applyStyle(XWPFRun run, XWPFParagraph  para, Map<String, Object> styleMap) {
        if (styleMap == null || styleMap.isEmpty()) {
            return;
        }

        if ("bold".equals(styleMap.get("font-weight")) || Boolean.TRUE.equals(styleMap.get("bold"))) {
            run.setBold(true);
        }

        if ("italic".equals(styleMap.get("font-style")) || Boolean.TRUE.equals(styleMap.get("italic"))) {
            run.setItalic(true);
        }

        if (styleMap.containsKey("color")) {
            String color = ((String) styleMap.get("color")).replace("#","");
            if(color.contains("rgb")){
                String[] rgb = color.replaceAll("rgb","").replaceAll("\\(","").replaceAll("\\)","").replaceAll("\\s+","").split(",");
                color = String.format("%02X%02X%02X", Integer.parseInt(rgb[0]), Integer.parseInt(rgb[1]), Integer.parseInt(rgb[2]));
            }
            // 将颜色名称转换为十六进制值
            String hexColor = convertColorNameToHex(color);
            run.setColor(hexColor);
        }

        if (styleMap.containsKey("font-size")) {
            //设置字体大小
            run.setFontSize(parseFontSize((String) styleMap.get("font-size")));
        }

        if (styleMap.containsKey("text-decoration-u")) {
            // 下划线
            run.setUnderline(UnderlinePatterns.SINGLE);
        }

        if (styleMap.containsKey("text-decoration-s")) {
            // 删除线
            run.setStrikeThrough(true);
        }
        if(styleMap.containsKey("text-align")){
            //文字居中、居左、居右
            para.setAlignment(textAlign((String)styleMap.get("text-align")));
        }
    }

    public static ParagraphAlignment textAlign(String align){
        switch (align) {
            case "center":return ParagraphAlignment.CENTER;
            case "end":return ParagraphAlignment.END;
            case "justify", "unset", "revert-layer", "revert", "initial", "inherit", "start":return ParagraphAlignment.START;
            case "right":return ParagraphAlignment.RIGHT;
            default:return ParagraphAlignment.LEFT;
        }
    }

    /**
     * 处理图片
     */
    private static void processImage(XWPFDocument document, Element element) {
        XWPFParagraph paragraph = document.createParagraph();
        String src = element.attr("src");
        if (src.startsWith("data:image")) {
            String[] parts = src.split(";base64,");
            if (parts.length == 2) {
                // 获取文件后缀
                String mimeType = parts[0];
                String suffix = mimeType.split("/")[1];
                // 解码 base64 字符串
                byte[] imageBytes = Base64.getDecoder().decode(parts[1]);

                // 添加图片到文档
                try {
                    XWPFRun run = paragraph.createRun();

                    // 添加图片到段落中，根据实际情况调整图片格式
                    int format = XWPFDocument.PICTURE_TYPE_JPEG;
                    // 图片文件名
                    String fileName = "image_" + System.currentTimeMillis() + "." + suffix;

                    // 获取图片的宽度和高度属性，限制最大600x400
                    Dimension dimensions = getAdjustedImageDimensions(imageBytes, 600, 400);
                    int width = dimensions.width;
                    int height = dimensions.height;

                    // 调整图片大小
                    run.addPicture(new ByteArrayInputStream(imageBytes), format, fileName, Units.toEMU(width), Units.toEMU(height));
                } catch (Exception e) {
                    log.error("添加图片到Word文档失败", e);
                }
            }
        }

    }


    /**
     * 获取图片尺寸并自动按最大宽高限制等比缩放
     *
     * @param imageBytes 图片字节数组
     * @param maxWidth   最大允许宽度（像素）
     * @param maxHeight  最大允许高度（像素）
     * @return 缩放后的尺寸对象（如果不需要缩放则返回原尺寸）
     * @throws Exception 图片解析失败抛出异常
     */
    public static Dimension getAdjustedImageDimensions(byte[] imageBytes, int maxWidth, int maxHeight) throws Exception {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes)) {
            BufferedImage image = ImageIO.read(bis);
            if (image == null) {
                throw new IllegalArgumentException("无法解析图片数据");
            }

            int originalWidth = image.getWidth();
            int originalHeight = image.getHeight();

            // 如果原始尺寸已经在限制范围内，则无需缩放
            if (originalWidth <= maxWidth && originalHeight <= maxHeight) {
                return new Dimension(originalWidth, originalHeight);
            }

            // 计算等比例缩放比例
            double widthRatio = (double) maxWidth / originalWidth;
            double heightRatio = (double) maxHeight / originalHeight;
            double ratio = Math.min(widthRatio, heightRatio);

            // 计算缩放后的尺寸
            int scaledWidth = (int) (originalWidth * ratio);
            int scaledHeight = (int) (originalHeight * ratio);

            return new Dimension(scaledWidth, scaledHeight);
        }
    }

    /**
     * 处理标题
     */
    private static void processHeading(XWPFDocument document, Element headingElement, Map<String, Object> styleMap) {
        String tagName = headingElement.tagName().toLowerCase();
        int headingLevel = Integer.parseInt(tagName.substring(1));
        XWPFParagraph paragraph = document.createParagraph();
        paragraph.setStyle("Heading" + headingLevel);
        addCustomHeadingStyle(document, "Heading" + headingLevel, headingLevel);

        roundProcessElement(headingElement, styleMap, paragraph);

    }

    /**
     * 处理段落
     */
    private static void processParagraph(XWPFDocument document, Element paragraphElement,
                                         Map<String, Object> styleMap, XWPFTableCell cell, BigInteger numId) {
        XWPFParagraph paragraph;
        if (null != cell) {
            //单元格cell中，td有p标签换行的情况
            paragraph = cell.getParagraphs().isEmpty() ?
                    cell.addParagraph() : cell.getParagraphs().get(0);
        } else {
            paragraph = document.createParagraph();
            if (null != numId) {
                // li下面的p标签
                if (numId.intValue() == -1) {
                    // 设置缩进
                    paragraph.setIndentationLeft(450);
                } else {
                    // 设置列表样式
                    paragraph.setNumID(numId);
                }
            }
        }
        roundProcessElement(paragraphElement, styleMap, paragraph);
    }

    /**
     * 递归子节点
     */
    private static void roundProcessElement(Element paragraphElement, Map<String, Object> styleMap, XWPFParagraph paragraph) {
        Map<String, Object> merged = mergeStyle(styleMap, parseStyle(paragraphElement));
        for (Node child : paragraphElement.childNodes()) {
            processElement(child, paragraph, merged, null, null);
        }
    }

    /**
     * 递归子节点
     */
    private static void roundProcessElementForTable(Element paragraphElement, Map<String, Object> styleMap, XWPFParagraph paragraph,
                                                    XWPFTableCell cell) {
        Map<String, Object> merged = mergeStyle(styleMap, parseStyle(paragraphElement));
        for (Node child : paragraphElement.childNodes()) {
            processElement(child, paragraph, merged, cell, null);
        }
    }

    /**
     * 处理列表
     */
    private static void processList(XWPFDocument document, Element listElement, Map<String, Object> styleMap) {
        boolean isOrdered = "ol".equalsIgnoreCase(listElement.tagName());
        // 动态生成唯一的 numID
        BigInteger numId = addListStyles(document, isOrdered);
        for (Element liElementChild : listElement.children()) {
            if ("li".equalsIgnoreCase(liElementChild.tagName())) {
                // 处理内容
                processElement(liElementChild, document.getLastParagraph(), styleMap, null, numId);
            }
        }
    }

    /**
     * 设置列表的样式
     */
    private static BigInteger addListStyles(XWPFDocument document, boolean isOrdered) {
        // 初始化文档的编号定义部分
        XWPFNumbering numbering = document.getNumbering();
        if (numbering == null) {
            numbering = document.createNumbering();
        }

        // 查找下一个可用的 abstractNumId
        BigInteger abstractNumId = BigInteger.valueOf(1);
        while (numbering.getAbstractNum(abstractNumId) != null) {
            abstractNumId = abstractNumId.add(BigInteger.ONE);
        }

        // 创建有序或无序列表样式
        CTAbstractNum ctAbstractNum = CTAbstractNum.Factory.newInstance();
        ctAbstractNum.setAbstractNumId(abstractNumId);
        CTLvl ctLvl = ctAbstractNum.addNewLvl();
        ctLvl.setIlvl(BigInteger.ZERO);

        if (isOrdered) {
            // 有序列表样式
            ctLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL);
            ctLvl.addNewLvlText().setVal("%1.");
            ctLvl.addNewStart().setVal(BigInteger.ONE);
        } else {
            // 无序列表样式
            ctLvl.addNewNumFmt().setVal(STNumberFormat.BULLET);
            ctLvl.addNewLvlText().setVal("•");
        }

        // 将样式添加到文档
        XWPFAbstractNum abstractNum = new XWPFAbstractNum(ctAbstractNum);
        numbering.addAbstractNum(abstractNum);
        return numbering.addNum(abstractNumId);
    }

    /**
     * 处理表格
     *
     * @param document     Word文档对象
     * @param tableElement HTML表格元素
     */
    private static void processTable(XWPFDocument document, Element tableElement, Map<String, Object> styleMap) {
        // 创建Word表格
        XWPFTable table = document.createTable();

        // 获取HTML表格的所有行
        Elements rows = tableElement.select("tr");

        // 存储合并信息（rowspan/colspan处理）
        int[][] mergeInfo = new int[rows.size()][];
        int maxCols = 0;

        // 第一遍：计算最大列数和初始化合并信息
        for (int i = 0; i < rows.size(); i++) {
            Elements cells = rows.get(i).select("td, th");
            mergeInfo[i] = new int[cells.size()];
            maxCols = Math.max(maxCols, cells.size());
        }

        // 第二遍：处理实际单元格内容
        for (int rowIdx = 0; rowIdx < rows.size(); rowIdx++) {
            Element row = rows.get(rowIdx);
            Elements cells = row.select("td, th");

            // 获取或创建Word表格行
            XWPFTableRow tableRow = rowIdx < table.getNumberOfRows() ?
                    table.getRow(rowIdx) : table.createRow();

            // 设置行高，增加行之间的间距
            tableRow.setHeight(400);

            int colIdx = 0;

            for (Element cell : cells) {
                // 处理rowspan和colspan
                int rowspan = Math.max(1, cell.hasAttr("rowspan") ?
                        Integer.parseInt(cell.attr("rowspan")) : 1);
                int colspan = Math.max(1, cell.hasAttr("colspan") ?
                        Integer.parseInt(cell.attr("colspan")) : 1);

                // 跳过被合并的单元格位置
                while (colIdx < mergeInfo[rowIdx].length && mergeInfo[rowIdx][colIdx] == 1) {
                    colIdx++;
                }

                // 获取或创建单元格
                XWPFTableCell tableCell = colIdx < tableRow.getTableCells().size() ?
                        tableRow.getCell(colIdx) : tableRow.addNewTableCell();

                // 设置单元格内容
                processCellContent(tableCell, cell, styleMap);

                // 处理合并
                if (rowspan > 1 || colspan > 1) {
                    mergeCells(table, rowIdx, colIdx, rowspan, colspan);
                }

                // 标记合并区域
                for (int r = 0; r < rowspan; r++) {
                    if (rowIdx + r >= mergeInfo.length) {
                        break;
                    }
                    for (int c = 0; c < colspan; c++) {
                        if (colIdx + c >= mergeInfo[rowIdx + r].length) {
                            break;
                        }
                        if (r == 0 && c == 0) {
                            continue; // 主单元格不标记
                        }
                        // 标记为被合并
                        mergeInfo[rowIdx + r][colIdx + c] = 1;
                    }
                }

                colIdx += colspan;
            }
        }

        // 设置表格样式（可选）
        setTableStyle(table);

    }

    /**
     * 处理单元格内容
     */
    private static void processCellContent(XWPFTableCell cell, Element htmlCell, Map<String, Object> styleMap) {
        // 清除默认段落（如果存在）
        if (!cell.getParagraphs().isEmpty()) {
            cell.removeParagraph(0);
        }

        // 创建新段落并设置内容
        XWPFParagraph para = cell.addParagraph();

        Map<String, Object> nextStyle = new HashMap<>(styleMap);
        // 可以添加更多样式处理
        if ("th".equals(htmlCell.tagName())) {
            nextStyle.put("bold", true);
        }
        // 垂直居中对齐
        cell.setVerticalAlignment(XWPFVertAlign.CENTER);

        // 递归
        roundProcessElementForTable(htmlCell, nextStyle, para, cell);

    }

    /**
     * 合并单元格（修复版，支持复杂合并）
     *
     * @param table   表格对象
     * @param row     起始行（0-based）
     * @param col     起始列（0-based）
     * @param rowspan 向下合并行数（≥1）
     * @param colspan 向右合并列数（≥1）
     */
    private static void mergeCells(XWPFTable table, int row, int col, int rowspan, int colspan) {
        // 1. 参数校验
        if (row < 0 || col < 0 || rowspan < 1 || colspan < 1) {
            throw new IllegalArgumentException("Invalid merge parameters: row=" + row + ", col=" + col
                    + ", rowspan=" + rowspan + ", colspan=" + colspan);
        }

        // 2. 动态扩展表格（修复可能的多行多列不足问题）
        for (int i = row; i < row + rowspan; i++) {
            // 处理行不足
            while (i >= table.getNumberOfRows()) {
                XWPFTableRow newRow = table.createRow();
                // 保持与首列相同的单元格数（避免列数不一致）
                if (table.getNumberOfRows() > 1) {
                    int firstRowCells = table.getRow(0).getTableCells().size();
                    while (newRow.getTableCells().size() < firstRowCells) {
                        newRow.createCell();
                    }
                }
            }

            // 处理列不足
            XWPFTableRow currentRow = table.getRow(i);
            for (int j = col; j < col + colspan; j++) {
                while (j >= currentRow.getTableCells().size()) {
                    currentRow.createCell();
                }
            }
        }

        // 3. 获取主单元格属性（确保存在）
        XWPFTableCell mainCell = table.getRow(row).getCell(col);
        CTTcPr mainTcPr = mainCell.getCTTc().isSetTcPr() ?
                mainCell.getCTTc().getTcPr() : mainCell.getCTTc().addNewTcPr();

        // 4. 仅当需要合并时操作
        if (rowspan > 1 || colspan > 1) {
            // 4.1 设置主单元格合并标记（修复重复添加属性问题）
            if (rowspan > 1) {
                if (mainTcPr.isSetVMerge()) {
                    mainTcPr.getVMerge().setVal(STMerge.RESTART);
                } else {
                    mainTcPr.addNewVMerge().setVal(STMerge.RESTART);
                }
            }
            if (colspan > 1) {
                if (mainTcPr.isSetHMerge()) {
                    mainTcPr.getHMerge().setVal(STMerge.RESTART);
                } else {
                    mainTcPr.addNewHMerge().setVal(STMerge.RESTART);
                }
            }

            // 4.2 处理被合并的单元格（优化内容清除方式）
            for (int i = row; i < row + rowspan; i++) {
                for (int j = col; j < col + colspan; j++) {
                    if (i == row && j == col) {
                        continue; // 主单元格不需要处理
                    }

                    XWPFTableCell cell = table.getRow(i).getCell(j);

                    // 高效清除内容（直接操作底层XML）
                    for (int k = cell.getParagraphs().size() - 1; k >= 0; k--) {
                        cell.removeParagraph(k);
                    }

                    // 获取或创建属性
                    CTTcPr tcPr = cell.getCTTc().isSetTcPr() ?
                            cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();

                    // 清除独立边框（避免渲染异常）
                    if (tcPr.isSetTcBorders()) {
                        tcPr.unsetTcBorders();
                    }

                    // 设置合并属性
                    if (rowspan > 1) {
                        if (tcPr.isSetVMerge()) {
                            tcPr.getVMerge().setVal(STMerge.CONTINUE);
                        } else {
                            tcPr.addNewVMerge().setVal(STMerge.CONTINUE);
                        }
                    }
                    if (colspan > 1) {
                        if (tcPr.isSetHMerge()) {
                            tcPr.getHMerge().setVal(STMerge.CONTINUE);
                        } else {
                            tcPr.addNewHMerge().setVal(STMerge.CONTINUE);
                        }
                    }
                }
            }

            // 4.3 确保主单元格有可见边框
            if (!mainTcPr.isSetTcBorders()) {
                CTTcBorders borders = mainTcPr.addNewTcBorders();
                borders.addNewLeft().setVal(STBorder.SINGLE);
                borders.addNewRight().setVal(STBorder.SINGLE);
                borders.addNewTop().setVal(STBorder.SINGLE);
                borders.addNewBottom().setVal(STBorder.SINGLE);
            }
        }
    }

    /**
     * 设置表格样式，包括单元格背景颜色、字体颜色、文本对齐方式等
     *
     * @param table Word表格对象
     */
    private static void setTableStyle(XWPFTable table) {
        // 1. 设置表格宽度为100%
        table.setWidth("100%");

        // 2. 设置表格边框（1px黑色实线，合并边框）
        setTableBorders(table);

        // 3. 设置表格单元格边距
        table.setCellMargins(60, 60, 60, 60);

        // 4. 设置表格整体属性
//        CTJc jc = table.getCTTbl().getTblPr().getJc();
//        if (jc == null) {
//            jc = table.getCTTbl().getTblPr().addNewJc();
//        }
//        //设置表格内容居中
//        jc.setVal(STJc.CENTER);
//        table.getCTTbl().getTblPr().setJc(jc);
    }

    /**
     * 设置表格边框
     */
    private static void setTableBorders(XWPFTable table) {
        CTTblPr tblPr = table.getCTTbl().getTblPr();
        if (tblPr == null) {
            tblPr = table.getCTTbl().addNewTblPr();
        }

        CTTblBorders borders = tblPr.isSetTblBorders() ? tblPr.getTblBorders() : tblPr.addNewTblBorders();

        // 设置所有边框（1px黑色实线）
        setBorder(borders.addNewTop());
        setBorder(borders.addNewLeft());
        setBorder(borders.addNewBottom());
        setBorder(borders.addNewRight());
        setBorder(borders.addNewInsideH());
        setBorder(borders.addNewInsideV());
    }

    /**
     * 辅助方法：设置边框
     */
    private static void setBorder(CTBorder border) {
        border.setVal(STBorder.SINGLE);
        border.setColor("000000");
        border.setSz(BigInteger.valueOf(4));
        border.setSpace(BigInteger.ZERO);
    }

    /**
     * 解析字体大小
     */
    private static int parseFontSize(String value) {
        // 如果值是像素值，例如 "10px"
        if (value.endsWith("px")) {
            //px转换为pt
            int pxValue = Integer.parseInt(value.replace("px", "").trim());
            return (int) (pxValue * 0.75);
        } else if (value.endsWith("pt")) {
            return Integer.parseInt(value.replace("pt", "").trim());
        }
        // 如果是其他类型的 font-size，可以在这里处理（例如 em, rem 等）
        return 10;
    }

    /**
     * 创建水平线
     */
    private static void createHorizontalRule(XWPFDocument document) {
        XWPFParagraph hrParagraph = document.createParagraph();
        XWPFRun run = hrParagraph.createRun();
        run.addBreak();
        run.addBreak(BreakType.TEXT_WRAPPING);
    }

    /**
     * 创建换行
     */
    private static void createLineBreak(XWPFDocument document, XWPFTableCell cell) {
        XWPFParagraph paragraph;
        if (null != cell) {
            // 单元格内换行方案
            paragraph = cell.getParagraphs().isEmpty() ?
                    cell.addParagraph() : cell.getParagraphs().get(0);

            XWPFRun run = paragraph.createRun();
            run.addBreak(BreakType.TEXT_WRAPPING);
            run.setText("");
        } else {
            paragraph = document.createParagraph();
            paragraph.createRun().addBreak();
        }
    }

    /**
     * 增加自定义标题样式
     *
     * @param docxDocument 目标文档
     * @param strStyleId   样式名称
     * @param headingLevel 样式级别
     */
    private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
        // 1. 基础样式定义
        CTStyle ctStyle = CTStyle.Factory.newInstance();
        ctStyle.setStyleId(strStyleId);

        // 样式名称
        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(strStyleId);
        ctStyle.setName(styleName);

        // 大纲级别
        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));

        // 2. 设置样式显示属性
        ctStyle.setUiPriority(indentNumber);
        ctStyle.setUnhideWhenUsed(CTOnOff.Factory.newInstance());
        ctStyle.setQFormat(CTOnOff.Factory.newInstance());

        // 3. 段落属性（大纲级别）
//        CTPPr ppr = CTPPr.Factory.newInstance();
//        ppr.setOutlineLvl(indentNumber);
//        ctStyle.setPPr(ppr);

        // 4. 字体属性（关键新增部分）
        CTRPr rpr = CTRPr.Factory.newInstance();
        // 字体大小计算（h1=22pt, h2=20pt... h6=12pt）
        int fontSizePt = 22 - (Math.min(headingLevel, 6) - 1) * 2;
        rpr.addNewSz().setVal(BigInteger.valueOf(fontSizePt * 2L));
        rpr.addNewSzCs().setVal(BigInteger.valueOf(fontSizePt * 2L));
        // 默认加粗
//        rpr.addNewB().setVal(STOnOff.TRUE);
        ctStyle.setRPr(rpr);

        // 5. 添加到文档样式库
        XWPFStyle style = new XWPFStyle(ctStyle);
        style.setType(STStyleType.PARAGRAPH);
        XWPFStyles styles = docxDocument.createStyles();
        styles.addStyle(style);
    }

    /**
     * 将颜色名称转换为十六进制值
     */
    private static String convertColorNameToHex(String colorName) {
        switch (colorName.toLowerCase()) {
            case "red":
                return "FF0000";
            case "blue":
                return "0000FF";
            case "green":
                return "00FF00";
            case "black":
                return "000000";
            case "white":
                return "FFFFFF";
            case "yellow":
                return "FFFF00";
            case "gray":
            case "grey":
                return "808080";
            default:
                // 如果无法识别颜色名称，返回 原代码
                return colorName;
        }
    }

    /**
     * 样式集合
     */
    public static Map<String, Object> mergeStyle(Map<String, Object> parent, Map<String, Object> current) {
        Map<String, Object> merged = new HashMap<>();
        if (parent != null) {
            merged.putAll(parent);
        }
        if (current != null) {
            merged.putAll(current);
        }
        return merged;
    }

    /**
     * 解析样式
     */
    public static Map<String, Object> parseStyle(Element el) {
        Map<String, Object> map = new HashMap<>();
        String style = el.attr("style");
        if (StrUtil.isNotBlank(style)) {
            for (String s : style.split(";")) {
                String[] kv = s.split(":");
                if (kv.length == 2) {
                    map.put(kv[0].trim().toLowerCase(), kv[1].trim());
                }
            }
        }

        String tag = el.tagName().toLowerCase();
        switch (tag) {
            case "strong":
            case "b":
                map.put("font-weight", "bold");
                break;
            case "i":
            case "em":
                map.put("font-style", "italic");
                break;
            case "u":
                map.put("text-decoration-u", "underline");
                break;
            case "s":
                map.put("text-decoration-s", "line-through");
                break;
            default:
                break;
        }
        return map;
    }
}

